package com.kexilo.dict.service;

import com.kexilo.dict.domain.DictData;
import com.kexilo.dict.properties.DictProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 字典服务默认实现
 * 支持数据库、缓存、异步等多种处理方式
 * 
 * @author Kexilo
 */
public class DictServiceImpl implements DictService {
    
    private static final Logger log = LoggerFactory.getLogger(DictServiceImpl.class);
    
    private final DictProperties properties;
    private final JdbcTemplate jdbcTemplate;
    private final CacheManager cacheManager;
    
    // 缓存统计
    private final Map<String, Long> hitCount = new ConcurrentHashMap<>();
    private final Map<String, Long> missCount = new ConcurrentHashMap<>();
    
    public DictServiceImpl(DictProperties properties, 
                          JdbcTemplate jdbcTemplate, 
                          CacheManager cacheManager) {
        this.properties = properties;
        this.jdbcTemplate = jdbcTemplate;
        this.cacheManager = cacheManager;
        log.info("字典服务初始化完成，缓存策略: {}, 数据源类型: {}", 
                properties.getCacheStrategy(), properties.getDataSourceType());
    }
    
    @Override
    public List<DictData> selectDictDataByType(String dictType) {
        if (!StringUtils.hasText(dictType)) {
            return Collections.emptyList();
        }
        
        long startTime = System.currentTimeMillis();
        
        try {
            // 尝试从缓存获取
            List<DictData> cachedData = getFromCache(dictType);
            if (cachedData != null) {
                incrementHitCount(dictType);
                return cachedData;
            }
            
            incrementMissCount(dictType);
            
            // 从数据库查询
            List<DictData> dictDataList = queryFromDatabase(dictType);
            
            // 存入缓存
            putToCache(dictType, dictDataList);
            
            long costTime = System.currentTimeMillis() - startTime;
            log.debug("查询字典数据: {}, 耗时: {}ms, 数量: {}", dictType, costTime, dictDataList.size());
            
            // 慢查询监控
            if (properties.getMonitor().isEnabled() && 
                costTime > properties.getMonitor().getSlowQueryThreshold().toMillis()) {
                log.warn("字典查询慢查询告警: {}, 耗时: {}ms", dictType, costTime);
            }
            
            return dictDataList;
            
        } catch (Exception e) {
            log.error("查询字典数据失败: {}", dictType, e);
            return Collections.emptyList();
        }
    }
    
    @Override
    @Async("dictTaskExecutor")
    public CompletableFuture<List<DictData>> selectDictDataByTypeAsync(String dictType) {
        try {
            List<DictData> result = selectDictDataByType(dictType);
            return CompletableFuture.completedFuture(result);
        } catch (Exception e) {
            log.error("异步查询字典数据失败: {}", dictType, e);
            return CompletableFuture.failedFuture(e);
        }
    }
    
    @Override
    public Map<String, List<DictData>> selectDictDataByTypes(List<String> dictTypes) {
        if (dictTypes == null || dictTypes.isEmpty()) {
            return Collections.emptyMap();
        }
        
        Map<String, List<DictData>> result = new HashMap<>();
        
        if (properties.getDatabase().isBatchQueryEnabled() && dictTypes.size() > 1) {
            // 批量查询优化
            try {
                result = batchQueryFromDatabase(dictTypes);
            } catch (Exception e) {
                log.error("批量查询字典数据失败", e);
                // 降级到单个查询
                for (String dictType : dictTypes) {
                    result.put(dictType, selectDictDataByType(dictType));
                }
            }
        } else {
            // 单个查询
            for (String dictType : dictTypes) {
                result.put(dictType, selectDictDataByType(dictType));
            }
        }
        
        return result;
    }
    
    @Override
    public String selectDictLabel(String dictType, String dictValue) {
        if (!StringUtils.hasText(dictType) || !StringUtils.hasText(dictValue)) {
            return null;
        }
        
        List<DictData> dictDataList = selectDictDataByType(dictType);
        return dictDataList.stream()
                .filter(data -> dictValue.equals(data.getDictValue()))
                .map(DictData::getDictLabel)
                .findFirst()
                .orElse(null);
    }
    
    @Override
    public String selectDictValue(String dictType, String dictLabel) {
        if (!StringUtils.hasText(dictType) || !StringUtils.hasText(dictLabel)) {
            return null;
        }
        
        List<DictData> dictDataList = selectDictDataByType(dictType);
        return dictDataList.stream()
                .filter(data -> dictLabel.equals(data.getDictLabel()))
                .map(DictData::getDictValue)
                .findFirst()
                .orElse(null);
    }
    
    @Override
    public List<String> selectDictTypeAll() {
        try {
            String sql = "SELECT DISTINCT dict_type FROM " + properties.getDatabase().getDictDataTable() + 
                        " WHERE status = '1' ORDER BY dict_type";
            return jdbcTemplate.queryForList(sql, String.class);
        } catch (Exception e) {
            log.error("查询所有字典类型失败", e);
            return Collections.emptyList();
        }
    }
    
    @Override
    public void refreshCache(String dictType) {
        try {
            if (StringUtils.hasText(dictType)) {
                evictFromCache(dictType);
                selectDictDataByType(dictType); // 重新加载
                log.info("刷新字典缓存: {}", dictType);
            } else {
                clearAllCache();
                warmupCache(null);
                log.info("刷新所有字典缓存");
            }
        } catch (Exception e) {
            log.error("刷新字典缓存失败: {}", dictType, e);
        }
    }
    
    @Override
    public void warmupCache(List<String> dictTypes) {
        if (!properties.isWarmupEnabled()) {
            return;
        }
        
        try {
            List<String> typesToWarmup = dictTypes;
            if (typesToWarmup == null || typesToWarmup.isEmpty()) {
                // 使用配置的预热类型，或查询所有类型
                typesToWarmup = properties.getWarmupTypes().isEmpty() ? 
                               selectDictTypeAll() : properties.getWarmupTypes();
            }
            
            log.info("开始预热字典缓存，类型数量: {}", typesToWarmup.size());
            
            for (String dictType : typesToWarmup) {
                try {
                    selectDictDataByType(dictType);
                    log.debug("预热字典缓存: {}", dictType);
                } catch (Exception e) {
                    log.warn("预热字典缓存失败: {}", dictType, e);
                }
            }
            
            log.info("字典缓存预热完成");
            
        } catch (Exception e) {
            log.error("字典缓存预热失败", e);
        }
    }
    
    @Override
    public boolean exists(String dictType, String dictValue) {
        return StringUtils.hasText(selectDictLabel(dictType, dictValue));
    }
    
    @Override
    public DictData getDefault(String dictType) {
        List<DictData> dictDataList = selectDictDataByType(dictType);
        return dictDataList.stream()
                .filter(DictData::isDefaultOption)
                .findFirst()
                .orElse(dictDataList.isEmpty() ? null : dictDataList.get(0));
    }
    
    @Override
    public List<DictData> selectEnabledDictDataByType(String dictType) {
        List<DictData> dictDataList = selectDictDataByType(dictType);
        return dictDataList.stream()
                .filter(DictData::isEnabled)
                .collect(Collectors.toList());
    }
    
    @Override
    public Map<String, String> selectDictMap(String dictType) {
        List<DictData> dictDataList = selectDictDataByType(dictType);
        return dictDataList.stream()
                .filter(DictData::isEnabled)
                .collect(Collectors.toMap(
                    DictData::getDictValue, 
                    DictData::getDictLabel,
                    (existing, replacement) -> existing // 保留已存在的值
                ));
    }
    
    @Override
    public Map<String, String> selectDictReverseMap(String dictType) {
        List<DictData> dictDataList = selectDictDataByType(dictType);
        return dictDataList.stream()
                .filter(DictData::isEnabled)
                .collect(Collectors.toMap(
                    DictData::getDictLabel, 
                    DictData::getDictValue,
                    (existing, replacement) -> existing
                ));
    }
    
    @Override
    public boolean isAvailable() {
        try {
            if (jdbcTemplate != null) {
                jdbcTemplate.queryForObject("SELECT 1", Integer.class);
                return true;
            }
            return false;
        } catch (Exception e) {
            log.warn("字典服务不可用: {}", e.getMessage());
            return false;
        }
    }
    
    @Override
    public Map<String, Object> getCacheStats() {
        Map<String, Object> stats = new HashMap<>();
        
        long totalHits = hitCount.values().stream().mapToLong(Long::longValue).sum();
        long totalMisses = missCount.values().stream().mapToLong(Long::longValue).sum();
        long totalRequests = totalHits + totalMisses;
        
        stats.put("totalHits", totalHits);
        stats.put("totalMisses", totalMisses);
        stats.put("totalRequests", totalRequests);
        stats.put("hitRate", totalRequests > 0 ? (double) totalHits / totalRequests : 0.0);
        stats.put("hitCountByType", new HashMap<>(hitCount));
        stats.put("missCountByType", new HashMap<>(missCount));
        
        return stats;
    }
    
    @Override
    public void clearAllCache() {
        try {
            if (cacheManager != null) {
                Cache cache = cacheManager.getCache(properties.getCache().getCacheName());
                if (cache != null) {
                    cache.clear();
                }
            }
            hitCount.clear();
            missCount.clear();
            log.info("清除所有字典缓存");
        } catch (Exception e) {
            log.error("清除字典缓存失败", e);
        }
    }
    
    /**
     * 从数据库查询字典数据
     */
    private List<DictData> queryFromDatabase(String dictType) {
        String sql = "SELECT dict_code, dict_sort, dict_label, dict_value, dict_type, " +
                    "css_class, list_class, is_default, status, remark, " +
                    "create_by, create_time, update_by, update_time " +
                    "FROM " + properties.getDatabase().getDictDataTable() + 
                    " WHERE dict_type = ? AND status = '1' " +
                    "ORDER BY dict_sort ASC, dict_code ASC";
        
        return jdbcTemplate.query(sql, getDictDataRowMapper(), dictType);
    }
    
    /**
     * 批量查询字典数据
     */
    private Map<String, List<DictData>> batchQueryFromDatabase(List<String> dictTypes) {
        String inClause = dictTypes.stream()
                .map(type -> "?")
                .collect(Collectors.joining(","));
        
        String sql = "SELECT dict_code, dict_sort, dict_label, dict_value, dict_type, " +
                    "css_class, list_class, is_default, status, remark, " +
                    "create_by, create_time, update_by, update_time " +
                    "FROM " + properties.getDatabase().getDictDataTable() + 
                    " WHERE dict_type IN (" + inClause + ") AND status = '1' " +
                    "ORDER BY dict_type ASC, dict_sort ASC, dict_code ASC";
        
        List<DictData> allData = jdbcTemplate.query(sql, getDictDataRowMapper(), dictTypes.toArray());
        
        return allData.stream()
                .collect(Collectors.groupingBy(DictData::getDictType));
    }
    
    /**
     * DictData行映射器
     */
    private RowMapper<DictData> getDictDataRowMapper() {
        return (rs, rowNum) -> DictData.builder()
                .dictCode(rs.getLong("dict_code"))
                .dictSort(rs.getInt("dict_sort"))
                .dictLabel(rs.getString("dict_label"))
                .dictValue(rs.getString("dict_value"))
                .dictType(rs.getString("dict_type"))
                .cssClass(rs.getString("css_class"))
                .listClass(rs.getString("list_class"))
                .isDefault(rs.getString("is_default"))
                .status(rs.getString("status"))
                .remark(rs.getString("remark"))
                .createBy(rs.getString("create_by"))
                .createTime(rs.getTimestamp("create_time") != null ? 
                           rs.getTimestamp("create_time").toLocalDateTime() : null)
                .updateBy(rs.getString("update_by"))
                .updateTime(rs.getTimestamp("update_time") != null ? 
                           rs.getTimestamp("update_time").toLocalDateTime() : null)
                .build();
    }
    
    /**
     * 从缓存获取数据
     */
    @SuppressWarnings("unchecked")
    private List<DictData> getFromCache(String dictType) {
        if (properties.getCacheStrategy() == DictProperties.CacheStrategy.NONE || cacheManager == null) {
            return null;
        }
        
        try {
            Cache cache = cacheManager.getCache(properties.getCache().getCacheName());
            if (cache != null) {
                String cacheKey = properties.getCache().getKeyPrefix() + dictType;
                Cache.ValueWrapper wrapper = cache.get(cacheKey);
                if (wrapper != null) {
                    return (List<DictData>) wrapper.get();
                }
            }
        } catch (Exception e) {
            log.warn("从缓存获取数据失败: {}", dictType, e);
        }
        
        return null;
    }
    
    /**
     * 存入缓存
     */
    private void putToCache(String dictType, List<DictData> dictDataList) {
        if (properties.getCacheStrategy() == DictProperties.CacheStrategy.NONE || cacheManager == null) {
            return;
        }
        
        try {
            Cache cache = cacheManager.getCache(properties.getCache().getCacheName());
            if (cache != null) {
                String cacheKey = properties.getCache().getKeyPrefix() + dictType;
                cache.put(cacheKey, dictDataList);
            }
        } catch (Exception e) {
            log.warn("存入缓存失败: {}", dictType, e);
        }
    }
    
    /**
     * 从缓存中移除
     */
    private void evictFromCache(String dictType) {
        if (cacheManager == null) {
            return;
        }
        
        try {
            Cache cache = cacheManager.getCache(properties.getCache().getCacheName());
            if (cache != null) {
                String cacheKey = properties.getCache().getKeyPrefix() + dictType;
                cache.evict(cacheKey);
            }
        } catch (Exception e) {
            log.warn("从缓存移除失败: {}", dictType, e);
        }
    }
    
    /**
     * 增加命中计数
     */
    private void incrementHitCount(String dictType) {
        hitCount.merge(dictType, 1L, Long::sum);
    }
    
    /**
     * 增加未命中计数
     */
    private void incrementMissCount(String dictType) {
        missCount.merge(dictType, 1L, Long::sum);
    }
}
